<!DOCTYPE html>
<html>

<head>
    <title>React 复合组件通信方案</title>
    <meta charset='utf-8'>
    <link href='https://cdn.maxiang.io/res-min/themes/marxico.css' rel='stylesheet'>
    <style>
        #preview-contents {
            margin-top: -20px;
        }
    </style>
</head>

<body>
    <div id='preview-contents' class='note-content'>
        <h3 id="react-复合组件通信方案">React 复合组件通信方案</h3>

        <p>大前端时代下，项目开发中，基本都采用 “工程化” + “组件化”！</p>

        <p><strong>工程化</strong> <br>
            基于gulp、webpack、vite、rollup等，实现代码转换、文件优化、代码分割、模块合并、自动刷新、代码校验、自动发布等！</p>

        <p><strong>组件化</strong> <br>
            普通业务组件：SPA单页面应用、业务拆分等 <br>
            通用业务组件：具备复用性的业务模块 <br>
            通用功能组件：UI组件库中的组件 <br>
            ……</p>

        <p>而组件化开发中，必然会涉及 “父子组件、祖先和后代组件、平行组件、兄弟组件” 等，这就是所谓的 “复合组件”！我们今天要研究的话题就是：复合组件之间的通信(或数据传输)问题！！</p>

        <h4 id="1-基于props属性实现父子或兄弟组件间的通信">1. 基于props属性，实现父子(或兄弟)组件间的通信</h4>



        <p><img longdesc="./1659016677968.png" width="500" alt="Alt text" title="" type="image/png"
                src=""
                class=""></p>

        <p><strong>类组件</strong> <br>
            <code>Vote.jsx</code>
        </p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line">...
</div><div class="hljs-line">class Vote extends React.Component {
</div><div class="hljs-line">    <span class="hljs-comment">// 设置初始状态</span>
</div><div class="hljs-line">    state = {
</div><div class="hljs-line">        <span class="hljs-attr">supNum</span>: <span class="hljs-number">10</span>,
</div><div class="hljs-line">        <span class="hljs-attr">oppNum</span>: <span class="hljs-number">5</span>
</div><div class="hljs-line">    };
</div><div class="hljs-line">    <span class="hljs-comment">// 修改状态的方法</span>
</div><div class="hljs-line">    change = <span class="hljs-function"><span class="hljs-params">type</span> =&gt;</span> {
</div><div class="hljs-line">        <span class="hljs-keyword">let</span> { supNum, oppNum } = <span class="hljs-keyword">this</span>.state;
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (type === <span class="hljs-string">'sup'</span>) {
</div><div class="hljs-line">            <span class="hljs-keyword">this</span>.setState({ <span class="hljs-attr">supNum</span>: supNum + <span class="hljs-number">1</span> });
</div><div class="hljs-line">            <span class="hljs-keyword">return</span>;
</div><div class="hljs-line">        }
</div><div class="hljs-line">        <span class="hljs-keyword">this</span>.setState({ <span class="hljs-attr">oppNum</span>: oppNum + <span class="hljs-number">1</span> });
</div><div class="hljs-line">    };
</div><div class="hljs-line">    render() {
</div><div class="hljs-line">        <span class="hljs-keyword">let</span> { supNum, oppNum } = <span class="hljs-keyword">this</span>.state;
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> &lt;div className="vote-box"&gt;
</div><div class="hljs-line">            &lt;header className="header"&gt;
</div><div class="hljs-line">                &lt;h2 className="title"&gt;React真的很不错!!&lt;/h2&gt;
</div><div class="hljs-line">                &lt;span className="num"&gt;{supNum + oppNum}人&lt;/span&gt;
</div><div class="hljs-line">            &lt;/header&gt;
</div><div class="hljs-line">            &lt;VoteMain supNum={supNum} oppNum={oppNum} /&gt;
</div><div class="hljs-line">            &lt;VoteFooter change={this.change} /&gt;
</div><div class="hljs-line">        &lt;/div&gt;;
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div><div class="hljs-line">export default Vote;
</div></code></pre>

        <p><code>VoteMain.jsx</code></p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">'prop-types'</span>;
</div><div class="hljs-line"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">VoteMain</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">PureComponent</span> </span>{
</div><div class="hljs-line">    <span class="hljs-comment">// 初始化属性 &amp; 规则校验</span>
</div><div class="hljs-line">    <span class="hljs-keyword">static</span> defaultProps = {
</div><div class="hljs-line">        <span class="hljs-attr">supNum</span>: <span class="hljs-number">0</span>,
</div><div class="hljs-line">        <span class="hljs-attr">oppNum</span>: <span class="hljs-number">0</span>
</div><div class="hljs-line">    };
</div><div class="hljs-line">    <span class="hljs-keyword">static</span> propTypes = {
</div><div class="hljs-line">        <span class="hljs-attr">supNum</span>: PropTypes.number,
</div><div class="hljs-line">        <span class="hljs-attr">oppNum</span>: PropTypes.number
</div><div class="hljs-line">    };
</div><div class="hljs-line">    render() {
</div><div class="hljs-line">        <span class="hljs-keyword">let</span> { supNum, oppNum } = <span class="hljs-keyword">this</span>.props;
</div><div class="hljs-line">        <span class="hljs-keyword">let</span> total = supNum + oppNum,
</div><div class="hljs-line">            ratio = <span class="hljs-string">'--'</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (total &gt; <span class="hljs-number">0</span>) ratio = (supNum / total * <span class="hljs-number">100</span>).toFixed(<span class="hljs-number">2</span>) + <span class="hljs-string">'%'</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>支持人数：{supNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>反对人数：{oppNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>支持比率：{ratio}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> VoteMain;
</div></code></pre>

        <p><code>VoteFooter.jsx</code></p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">'prop-types'</span>;
</div><div class="hljs-line"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">VoteFooter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">PureComponent</span> </span>{
</div><div class="hljs-line">    <span class="hljs-comment">// 初始化属性 &amp; 规则校验</span>
</div><div class="hljs-line">    <span class="hljs-keyword">static</span> propTypes = {
</div><div class="hljs-line">        <span class="hljs-attr">change</span>: PropTypes.func.isRequired
</div><div class="hljs-line">    };
</div><div class="hljs-line">    render() {
</div><div class="hljs-line">        <span class="hljs-keyword">let</span> { change } = <span class="hljs-keyword">this</span>.props;
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"footer"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{change.bind(null,</span> '<span class="hljs-attr">sup</span>')}&gt;</span>支持<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{change.bind(null,</span> '<span class="hljs-attr">opp</span>')}&gt;</span>反对<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> VoteFooter;
</div></code></pre>

        <p><strong>函数组件</strong> <br>
            <code>Vote.jsx</code>
        </p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React, { useState, useCallback } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line">...
</div><div class="hljs-line">const Vote = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Vote</span>(<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">    <span class="hljs-comment">// 定义状态</span>
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> [supNum, setSupNum] = useState(<span class="hljs-number">10</span>),
</div><div class="hljs-line">        [oppNum, setOppNum] = useState(<span class="hljs-number">5</span>);
</div><div class="hljs-line">    <span class="hljs-comment">// 定义修改状态的函数</span>
</div><div class="hljs-line">    <span class="hljs-keyword">const</span> change = useCallback(<span class="hljs-function"><span class="hljs-params">type</span> =&gt;</span> {
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (type === <span class="hljs-string">'sup'</span>) {
</div><div class="hljs-line">            setSupNum(supNum + <span class="hljs-number">1</span>);
</div><div class="hljs-line">            <span class="hljs-keyword">return</span>;
</div><div class="hljs-line">        }
</div><div class="hljs-line">        setOppNum(oppNum + <span class="hljs-number">1</span>);
</div><div class="hljs-line">    }, [supNum, oppNum]);
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> &lt;div className="vote-box"&gt;
</div><div class="hljs-line">        &lt;header className="header"&gt;
</div><div class="hljs-line">            &lt;h2 className="title"&gt;React真的很不错!!&lt;/h2&gt;
</div><div class="hljs-line">            &lt;span className="num"&gt;{supNum + oppNum}人&lt;/span&gt;
</div><div class="hljs-line">        &lt;/header&gt;
</div><div class="hljs-line">        &lt;VoteMain supNum={supNum} oppNum={oppNum} /&gt;
</div><div class="hljs-line">        &lt;VoteFooter change={change} /&gt;
</div><div class="hljs-line">    &lt;/div&gt;;
</div><div class="hljs-line">};
</div><div class="hljs-line">export default Vote;
</div></code></pre>

        <p><code>VoteMain.jsx</code></p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React, { useMemo } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">'prop-types'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">const</span> VoteMain = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">VoteMain</span>(<span class="hljs-params">props</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-comment">// 获取传递的属性值</span>
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> { supNum, oppNum } = props;
</div><div class="hljs-line">    <span class="hljs-comment">// 计算/缓存支持比率</span>
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> ratio = useMemo(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
</div><div class="hljs-line">        <span class="hljs-keyword">let</span> total = supNum + oppNum;
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> total &gt; <span class="hljs-number">0</span> ? (supNum / total * <span class="hljs-number">100</span>).toFixed(<span class="hljs-number">2</span>) + <span class="hljs-string">'%'</span> : <span class="hljs-string">'--'</span>;
</div><div class="hljs-line">    }, [supNum, oppNum]);
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>支持人数：{supNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>反对人数：{oppNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>支持比率：{ratio}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-comment">// 初始化属性 &amp; 规则校验</span>
</div><div class="hljs-line">VoteMain.defaultProps = {
</div><div class="hljs-line">    <span class="hljs-attr">supNum</span>: <span class="hljs-number">0</span>,
</div><div class="hljs-line">    <span class="hljs-attr">oppNum</span>: <span class="hljs-number">0</span>
</div><div class="hljs-line">};
</div><div class="hljs-line">VoteMain.propTypes = {
</div><div class="hljs-line">    <span class="hljs-attr">supNum</span>: PropTypes.number,
</div><div class="hljs-line">    <span class="hljs-attr">oppNum</span>: PropTypes.number
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> VoteMain;
</div></code></pre>

        <p><code>VoteFooter.jsx</code></p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React, { memo } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">'prop-types'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">const</span> VoteFooter = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">VoteFooter</span>(<span class="hljs-params">props</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> { change } = props;
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"footer"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{change.bind(null,</span> '<span class="hljs-attr">sup</span>')}&gt;</span>支持<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{change.bind(null,</span> '<span class="hljs-attr">opp</span>')}&gt;</span>反对<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-comment">// 初始化属性 &amp; 规则校验</span>
</div><div class="hljs-line">VoteFooter.propTypes = {
</div><div class="hljs-line">    <span class="hljs-attr">change</span>: PropTypes.func.isRequired
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> memo(VoteFooter);
</div></code></pre>

        <p><strong>单向数据流</strong></p>

        <p>理解一：属性的传递方向是单向的</p>

        <ul>
            <li>
                <p>父组件可基于属性把信息传给子组件</p>
            </li>
            <li>
                <p>子组件无法基于属性给父组件传信息；但可以把父组件传递的方法执行，从而实现子改父！</p>
            </li>
        </ul>

        <p>理解二：关于生命周期函数的延续</p>

        <ul>
            <li>
                <p>组件第一次渲染</p>

                <ul>
                    <li>
                        <p>父 willMount -&gt; 父 render</p>
                    </li>
                    <li>
                        <p>子 willMount -&gt; 子 render -&gt; 子 didMount</p>
                    </li>
                    <li>
                        <p>父 didMount</p>
                    </li>
                </ul>
            </li>
            <li>
                <p>组件更新</p>

                <ul>
                    <li>
                        <p>父 shouldUpdate -&gt; 父 willUpdate -&gt; 父 render</p>
                    </li>
                    <li>
                        <p>子 willReciveProps -&gt; 子 shouldUpdate -&gt; 子 willUpdate -&gt; 子 render -&gt; 子 didUpdate
                        </p>
                    </li>
                    <li>
                        <p>父 didUpdate</p>
                    </li>
                </ul>
            </li>
        </ul>

        <hr>

        <h4 id="2-基于context上下文实现祖先后代或平行组件间的通信">2. 基于context上下文，实现祖先/后代(或平行)组件间的通信</h4>



        <p><img longdesc="./1659019562795.png" width="500" alt="Alt text" title="" type="image/png"
                src=""
                class=""></p>

        <p><code>ThemeContext.js</code></p>



        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-comment">// 创建上下文对象</span>
</div><div class="hljs-line"><span class="hljs-keyword">import</span> { createContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">const</span> ThemeContext = createContext();
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ThemeContext;
</div></code></pre>

        <p><strong>类组件</strong> <br>
            <code>Vote.jsx</code>
        </p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line">...
</div><div class="hljs-line">import ThemeContext <span class="hljs-keyword">from</span> <span class="hljs-string">'@/ThemeContext'</span>;
</div><div class="hljs-line"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vote</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
</div><div class="hljs-line">    <span class="hljs-comment">// 设置初始状态</span>
</div><div class="hljs-line">    state = {
</div><div class="hljs-line">        <span class="hljs-attr">supNum</span>: <span class="hljs-number">10</span>,
</div><div class="hljs-line">        <span class="hljs-attr">oppNum</span>: <span class="hljs-number">5</span>
</div><div class="hljs-line">    };
</div><div class="hljs-line">    <span class="hljs-comment">// 修改状态的方法</span>
</div><div class="hljs-line">    change = <span class="hljs-function"><span class="hljs-params">type</span> =&gt;</span> {
</div><div class="hljs-line">        <span class="hljs-keyword">let</span> { supNum, oppNum } = <span class="hljs-keyword">this</span>.state;
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (type === <span class="hljs-string">'sup'</span>) {
</div><div class="hljs-line">            <span class="hljs-keyword">this</span>.setState({ <span class="hljs-attr">supNum</span>: supNum + <span class="hljs-number">1</span> });
</div><div class="hljs-line">            <span class="hljs-keyword">return</span>;
</div><div class="hljs-line">        }
</div><div class="hljs-line">        <span class="hljs-keyword">this</span>.setState({ <span class="hljs-attr">oppNum</span>: oppNum + <span class="hljs-number">1</span> });
</div><div class="hljs-line">    };
</div><div class="hljs-line">    render() {
</div><div class="hljs-line">        <span class="hljs-keyword">let</span> { supNum, oppNum } = <span class="hljs-keyword">this</span>.state;
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThemeContext.Provider</span></span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span></span>
</div><div class="hljs-line"><span class="xml">                <span class="hljs-attr">supNum</span>,</span>
</div><div class="hljs-line"><span class="xml">                <span class="hljs-attr">oppNum</span>,</span>
</div><div class="hljs-line"><span class="xml">                <span class="hljs-attr">change:</span> <span class="hljs-attr">this.change</span></span>
</div><div class="hljs-line"><span class="xml">            }}&gt;</span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"vote-box"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"title"</span>&gt;</span>React真的很不错!!<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"num"</span>&gt;</span>{supNum + oppNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                <span class="hljs-tag">&lt;<span class="hljs-name">VoteMain</span> /&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                <span class="hljs-tag">&lt;<span class="hljs-name">VoteFooter</span> /&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;/<span class="hljs-name">ThemeContext.Provider</span>&gt;</span>;</span>
</div><div class="hljs-line"><span class="xml">    }</span>
</div><div class="hljs-line"><span class="xml">};</span>
</div><div class="hljs-line"><span class="xml">export default Vote;</span>
</div></code></pre>

        <p><code>VoteMain.jsx</code></p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> ThemeContext <span class="hljs-keyword">from</span> <span class="hljs-string">'@/ThemeContext'</span>;
</div><div class="hljs-line"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">VoteMain</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
</div><div class="hljs-line">    <span class="hljs-comment">// 获取上下文信息</span>
</div><div class="hljs-line">    <span class="hljs-keyword">static</span> contextType = ThemeContext;
</div><div class="hljs-line">    render() {
</div><div class="hljs-line">        <span class="hljs-keyword">let</span> { supNum, oppNum } = <span class="hljs-keyword">this</span>.context;
</div><div class="hljs-line">        <span class="hljs-keyword">let</span> total = supNum + oppNum,
</div><div class="hljs-line">            ratio = <span class="hljs-string">'--'</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (total &gt; <span class="hljs-number">0</span>) ratio = (supNum / total * <span class="hljs-number">100</span>).toFixed(<span class="hljs-number">2</span>) + <span class="hljs-string">'%'</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>支持人数：{supNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>反对人数：{oppNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>支持比率：{ratio}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">    }
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> VoteMain;
</div></code></pre>

        <p><code>VoteFooter.jsx</code></p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> ThemeContext <span class="hljs-keyword">from</span> <span class="hljs-string">'@/ThemeContext'</span>;
</div><div class="hljs-line"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">VoteFooter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
</div><div class="hljs-line">    render() {
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThemeContext.Consumer</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            {context =&gt; {</span>
</div><div class="hljs-line"><span class="xml">                let { change } = context;</span>
</div><div class="hljs-line"><span class="xml">                return <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"footer"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{change.bind(null,</span> '<span class="hljs-attr">sup</span>')}&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                        支持</span>
</div><div class="hljs-line"><span class="xml">                    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{change.bind(null,</span> '<span class="hljs-attr">opp</span>')}&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                        反对</span>
</div><div class="hljs-line"><span class="xml">                    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>;</span>
</div><div class="hljs-line"><span class="xml">            }}</span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;/<span class="hljs-name">ThemeContext.Consumer</span>&gt;</span>;</span>
</div><div class="hljs-line"><span class="xml">    }</span>
</div><div class="hljs-line"><span class="xml">};</span>
</div><div class="hljs-line"><span class="xml">export default VoteFooter;</span>
</div></code></pre>

        <p><strong>函数组件</strong> <br>
            <code>Vote.jsx</code>
        </p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line">...
</div><div class="hljs-line">import ThemeContext <span class="hljs-keyword">from</span> <span class="hljs-string">'@/ThemeContext'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">const</span> Vote = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Vote</span>(<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> [supNum, setSupNum] = useState(<span class="hljs-number">10</span>),
</div><div class="hljs-line">        [oppNum, setOppNum] = useState(<span class="hljs-number">5</span>);
</div><div class="hljs-line">    <span class="hljs-keyword">const</span> change = <span class="hljs-function"><span class="hljs-params">type</span> =&gt;</span> {
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (type === <span class="hljs-string">'sup'</span>) {
</div><div class="hljs-line">            setSupNum(supNum + <span class="hljs-number">1</span>);
</div><div class="hljs-line">            <span class="hljs-keyword">return</span>;
</div><div class="hljs-line">        }
</div><div class="hljs-line">        setOppNum(oppNum + <span class="hljs-number">1</span>);
</div><div class="hljs-line">    };
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThemeContext.Provider</span></span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-attr">supNum</span>,</span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-attr">oppNum</span>,</span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-attr">change</span></span>
</div><div class="hljs-line"><span class="xml">        }}&gt;</span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"vote-box"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"header"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"title"</span>&gt;</span>React真的很不错!!<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"num"</span>&gt;</span>{supNum + oppNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">VoteMain</span> /&gt;</span></span>
</div><div class="hljs-line"><span class="xml">            <span class="hljs-tag">&lt;<span class="hljs-name">VoteFooter</span> /&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;/<span class="hljs-name">ThemeContext.Provider</span>&gt;</span>;</span>
</div><div class="hljs-line"><span class="xml">};</span>
</div><div class="hljs-line"><span class="xml">export default Vote;</span>
</div></code></pre>

        <p><code>VoteMain.jsx</code></p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React, { useContext, useMemo } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> ThemeContext <span class="hljs-keyword">from</span> <span class="hljs-string">'@/ThemeContext'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">const</span> VoteMain = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">VoteMain</span>(<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">    <span class="hljs-comment">// 获取上下文中的信息</span>
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> { supNum, oppNum } = useContext(ThemeContext);
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> ratio = useMemo(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> {
</div><div class="hljs-line">        <span class="hljs-keyword">let</span> total = supNum + oppNum;
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> total &gt; <span class="hljs-number">0</span> ? (supNum / total * <span class="hljs-number">100</span>).toFixed(<span class="hljs-number">2</span>) + <span class="hljs-string">'%'</span> : <span class="hljs-string">'--'</span>;
</div><div class="hljs-line">    }, [supNum, oppNum]);
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"main"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>支持人数：{supNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>反对人数：{oppNum}人<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>支持比率：{ratio}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> VoteMain;
</div></code></pre>

        <p><code>VoteFooter.jsx</code></p>

        <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">import</span> ThemeContext <span class="hljs-keyword">from</span> <span class="hljs-string">'@/ThemeContext'</span>;
</div><div class="hljs-line"><span class="hljs-keyword">const</span> VoteFooter = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">VoteFooter</span>(<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> { change } = useContext(ThemeContext);
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"footer"</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{change.bind(null,</span> '<span class="hljs-attr">sup</span>')}&gt;</span>支持<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{change.bind(null,</span> '<span class="hljs-attr">opp</span>')}&gt;</span>反对<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
</div><div class="hljs-line"><span class="xml">    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</div><div class="hljs-line">};
</div><div class="hljs-line"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> VoteFooter;
</div></code></pre>

        <hr>

        <p>在真实项目中</p>

        <ul>
            <li>
                <p>父子通信（或具备相同父亲的兄弟组件）：我们一般都是基于props属性实现</p>
            </li>
            <li>
                <p>其他组件之间的通信：我们都是基于 redux / react-redux 或者 mobx 去实现</p>
            </li>
        </ul>

        <p>后面的课程中，我们会详细讲解 redux / react-redux 等内容！！</p>
    </div>
</body>

</html>